package com.sojson.util.zookeeper;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.apache.curator.framework.AuthInfo;
import org.apache.zookeeper.data.Stat;

import com.sojson.constant.Constant;
import com.sojson.util.zookeeper.constant.ZooConstant;
import com.sojson.util.zookeeper.impl.CuratorFrameworkImpl;

import cn.hutool.core.convert.Convert;

/**
 * Zookeeper工具类
 * 
 * @author liu
 * @date 2020-11-15
 */
public class ZookeeperUtil {

    /** Zookeeper服务器地址 */
    public static final String URL = Constant.PROPERTIES.getProperty("so.zookeeper.url");
    /** Zookeeper服务器帐号 */
    public static final String USERNAME =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.zookeeper.username"), "root");
    /** Zookeeper服务器密码 */
    public static final String PASSWORD =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.zookeeper.password"), "123456");
    /** 等待连接成功的最大超时时间单位 */
    public static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
    private static final ZookeeperUtilInterface ZOOKEEPER_UTIL_INTERFACE =
        CuratorFrameworkImpl.getInstancesSingle().addAcl().open();

    /**
     * 给Zookeeper添加帐号密码
     * 
     * @return
     * @throws Exception
     */
    public static ZookeeperUtilInterface addAcl() {
        return ZOOKEEPER_UTIL_INTERFACE.addAcl();
    }

    /**
     * 给Zookeeper添加帐号密码
     * 
     * @param auth 帐号:密码
     * @return
     * @throws Exception
     */
    public static ZookeeperUtilInterface addAcl(String auth) {
        return ZOOKEEPER_UTIL_INTERFACE.addAcl(auth);
    }

    /**
     * 给Zookeeper添加帐号密码
     * 
     * @param auth 帐号:密码
     * @return
     * @throws Exception
     */
    public static ZookeeperUtilInterface addAcl(byte[] auth) {
        return ZOOKEEPER_UTIL_INTERFACE.addAcl(auth);
    }

    /**
     * 给Zookeeper添加帐号密码
     * 
     * @param username 帐号
     * @param password 密码
     * @return
     * @throws Exception
     */
    public static ZookeeperUtilInterface addAcl(String username, String password) {
        return ZOOKEEPER_UTIL_INTERFACE.addAcl(username, password);
    }

    /**
     * 同步创建一个持久节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static String create(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.create(path);
    }

    /**
     * 同步创建一个持久节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return 
     * @return
     * @throws Exception
     */
    public static String createByte(String path, byte[] data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createByte(path, data);
    }

    /**
     * 同步创建一个持久节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String create(String path, String data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.create(path, data);
    }

    /**
     * 同步创建一个持久顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static String createSort(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path);
    }

    /**
     * 同步创建一个持久顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createSortByte(String path, byte[] data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSortByte(path, data);
    }

    /**
     * 同步创建一个持久顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createSort(String path, String data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path, data);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点
     * 
     * @param path      节点
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSort(String path, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path, timeOut);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点,同时注册监听
     * 
     * @param path      节点
     * @param stat      节点信息
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSort(String path, Stat stat, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path, stat, timeOut);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点
     * 
     * @param path      节点
     * @param data   内容
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSort(String path, String data, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path, data, timeOut);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点
     * 
     * @param path      节点
     * @param data   内容
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSortByte(String path, byte[] data, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSortByte(path, data, timeOut);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点,同时注册监听
     * 
     * @param path      节点
     * @param data   内容
     * @param stat      节点信息
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSort(String path, String data, Stat stat, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSort(path, data, stat, timeOut);
    }

    /**
     * 同步创建一个有效时间的持久顺序节点,同时注册监听
     * 
     * @param path      节点
     * @param data   内容
     * @param stat      节点信息
     * @param timeOut   超时时间(单位: 毫秒)
     * @return
     * @throws Exception
     */
    public static String createSortByte(String path, byte[] data, Stat stat, long timeOut) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createSortByte(path, data, stat, timeOut);
    }

    /**
     * 同步创建一个临时节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static String createTemporary(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporary(path);
    }

    /**
     * 同步创建一个临时节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createTemporaryByte(String path, byte[] data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporaryByte(path, data);
    }

    /**
     * 同步创建一个临时节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createTemporary(String path, String data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporary(path, data);
    }

    /**
     * 同步创建一个临时顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static String createTemporarySort(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporarySort(path);
    }

    /**
     * 同步创建一个临时顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createTemporarySortByte(String path, byte[] data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporarySortByte(path, data);
    }

    /**
     * 同步创建一个临时顺序节点,ACL为 world:anyone:cdrwa 等同于如下命令: 
     * create path data world:anyone:cdrwa
     * 
     * @param path 节点
     * @param data 内容
     * @return
     * @throws Exception
     */
    public static String createTemporarySort(String path, String data) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.createTemporarySort(path, data);
    }

    /**
     * 删除节点
     * 
     * @param path 节点
     * @throws Exception 
     */
    public static void delete(String path) throws Exception {
        ZOOKEEPER_UTIL_INTERFACE.delete(path);
    }

    /**
     * 修改节点内容
     * 
     * @param path 节点
     * @param data 内容
     * @throws Exception 
     */
    public static void setData(String path, byte[] data) throws Exception {
        ZOOKEEPER_UTIL_INTERFACE.setData(path, data);
    }

    /**
     * 修改节点内容
     * 
     * @param path 节点
     * @param data 内容
     * @throws Exception 
     */
    public static void setData(String path, String data) throws Exception {
        ZOOKEEPER_UTIL_INTERFACE.setData(path, data);
    }

    /**
     * 获取指定节点的所有子节点(不注册监听)
     * 
     * @param path 节点
     * @param stat 通过exists查出来的对象
     * @return
     * @throws Exception
     */
    public static byte[] getData(String path, Stat stat) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getData(path, stat);
    }

    /**
     * 获取指定节点的所有子节点(同时注册监听)
     * 
     * @param path 节点
     * @param stat 通过exists查出来的对象
     * @return
     * @throws Exception
     */
    public static byte[] getDataTrue(String path, Stat stat) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getDataTrue(path, stat);
    }

    /**
     * 获取指定节点的所有子节点(同时注册监听)
     * 
     * @param path 节点
     * @param watcher 监视器
     * @param stat 通过exists查出来的对象
     * @return
     * @throws Exception
     */
    public static byte[] getData(String path, CustomWatcher watcher, Stat stat) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getData(path, watcher, stat);
    }

    /**
     * 获取指定节点的所有子节点(不注册监听)
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static List<String> getChildren(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getChildren(path);
    }

    /**
     * 获取指定节点的所有子节点(同时注册监听)
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static List<String> getChildrenTrue(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getChildrenTrue(path);
    }

    /**
     * 获取指定节点的所有子节点(同时注册监听)
     * 
     * @param path 节点
     * @param watcher 
     * @return
     * @throws Exception
     */
    public static List<String> getChildren(String path, CustomWatcher watcher) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.getChildren(path, watcher);
    }

    /**
     * 判断节点是否存在(不注册监听)
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static Stat exists(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.exists(path);
    }

    /**
     * 判断节点是否存在(同时注册监听)
     * 
     * @param path 节点
     * @return
     * @throws Exception
     */
    public static Stat existsTrue(String path) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.existsTrue(path);
    }

    /**
     * 判断节点是否存在(同时注册监听)
     * 
     * @param path 节点
     * @param watcher 
     * @return
     * @throws Exception
     */
    public static Stat exists(String path, CustomWatcher watcher) throws Exception {
        return ZOOKEEPER_UTIL_INTERFACE.exists(path, watcher);
    }

    /**
     * 获取ZooKeeper
     * 
     * @return 
     */
    public static ZookeeperUtilInterface getInstances() {
        return ZOOKEEPER_UTIL_INTERFACE.getInstances();
    }

    /**
     * 获取ZooKeeper
     * 
     * @param url 连接地址
     * @return 
     */
    public static ZookeeperUtilInterface getInstances(String url) {
        return ZOOKEEPER_UTIL_INTERFACE.getInstances(url);
    }

    /**
     * 获取ZooKeeper
     * 
     * @param watcher 监视器
     * @param countDownLatch 因为连接需要时间,所以需要在连接的时候暂停线程,连接成功后会有个回调方法,在回调方法中让计数减一后变成0恢复线程
     * @return 
     */
    public static ZookeeperUtilInterface getInstances(CustomWatcher watcher, CountDownLatch countDownLatch) {
        return ZOOKEEPER_UTIL_INTERFACE.getInstances(watcher, countDownLatch);
    }

    /**
     * 获取ZooKeeper
     * 
     * @param url 连接地址
     * @param watcher 监视器
     * @param countDownLatch 因为连接需要时间,所以需要在连接的时候暂停线程,连接成功后会有个回调方法,在回调方法中让计数减一后变成0恢复线程
     * @return 
     */
    public static ZookeeperUtilInterface getInstances(String url, CustomWatcher watcher,
        CountDownLatch countDownLatch) {
        return ZOOKEEPER_UTIL_INTERFACE.getInstances(url, watcher, countDownLatch);
    }

    /**
     * 获取用户权限
     * 
     * @return
     */
    public static String getAclDigest() {
        return getAclDigest(USERNAME, PASSWORD);
    }

    /**
     * 获取用户权限
     * 
     * @param username
     * @param password
     * @return
     */
    public static String getAclDigest(String username, String password) {
        return new StringBuilder(ZookeeperUtil.USERNAME).append(":").append(ZookeeperUtil.PASSWORD).toString();
    }

    /**
     * 获取用户权限
     * 
     * @return
     */
    public static byte[] getAclDigestByte() {
        return getAclDigestByte(USERNAME, PASSWORD);
    }

    /**
     * 获取用户权限
     * 
     * @param username
     * @param password
     * @return
     */
    public static byte[] getAclDigestByte(String username, String password) {
        return getAclDigest(username, password).getBytes();
    }

    /**
     * 获取权限列表
     * 
     * @return
     */
    public static List<AuthInfo> getAcls() {
        List<AuthInfo> acls = new ArrayList<>();

        AuthInfo authInfo = new AuthInfo(ZooConstant.SCHEME_DIGEST, ZookeeperUtil.getAclDigestByte());
        acls.add(authInfo);

        return acls;
    }

}